package main_package;

import java.util.ArrayList;

import genetic_algorithm.Chromosome;

/**
 * this class represents a chromosome for the Griddlers problem -
 * the basic representation - a matrix with binary values
 */
public class GriddlersChromosome extends Chromosome 
{
	// an array for holding the row constrains in the problem
	public static ArrayList<ArrayList<Integer>> row_cons;
	// an array for holding the column constrains in the problem
	public static ArrayList<ArrayList<Integer>> col_cons;
	// this chromosome solution board for this griddler
	public ArrayList<ArrayList<Integer>> board_sol;

	/**
	 * this class default constructor
	 * @param route - this chromosome board solution
	 */
	public GriddlersChromosome(ArrayList<ArrayList<Integer>> board_sol) 
	{
		this.board_sol = board_sol;
	}

	
	/**
	 * this function return this chromosome data - the board solution
	 */
	@Override
	public ArrayList<ArrayList<Integer>> getData() 
	{
		return board_sol;
	}

	/**
	 * this function calculate the fitness of this chromosome by
	 * counting the number of constraints this board support
	 */
	@Override
	public double evaluateFitness()
	{
		// initializing variables
		double fitness = 0;
		int last_color = -1, black=0;
		int row_size = row_cons.size();
		int col_size = col_cons.size();
		ArrayList<Integer> temp, temp2;
		ArrayList<Integer> curr_cons;

		// for every row in the matrix
		for (int i = 0; i < row_size; i++) 
		{
			temp = board_sol.get(i);
			curr_cons = new ArrayList<Integer>();
			// for every cell in the current matrix row
			for (int j = 0; j < col_size; j++)
			{
				//the case that the cell is white
				if(temp.get(j) == 0)
				{
					// the case that the old cell was black
					if(last_color == 1)
					{
						// add the constraint
						curr_cons.add(black);
						last_color = 0;
						black = 0;
					}
					// the case that this is the first cell or the old cell is white
					else
					{
						last_color = 0;
					}
				}
				// the case that the cell is black
				else
				{
					last_color = 1;
					black++;
				}
			}
			
			// the case that the old cell was black
			if(last_color == 1)
			{
				// add the constraint
				curr_cons.add(black);
			}
			
			last_color = -1;
			black = 0;
			
			temp2 = row_cons.get(i);
			//the case that the number of constraint in this board row and the problem matches
			if(curr_cons.size() == temp2.size())
			{
				// for every constrint
				for(int k = 0; k < temp2.size(); k++)
				{
					// the case that the constriants matches
					if(curr_cons.get(k) == temp2.get(k))
					{
						fitness+=col_size;
					}
				}
			}
			curr_cons.clear();
		}

		
		// now checking the columns
		ArrayList<ArrayList<Integer>> board_sol2 = transpose();
		last_color = -1;
		black = 0;
		
		// for every col in the matrix
		for (int i = 0; i < col_size; i++) 
		{
			temp = board_sol2.get(i);
			curr_cons = new ArrayList<Integer>();
			// for every cell in the current matrix col
			for (int j = 0; j < row_size; j++)
			{
				//the case that the cell is white
				if(temp.get(j) == 0)
				{
					// the case that the old cell was black
					if(last_color == 1)
					{
						// add the constraint
						curr_cons.add(black);
						last_color = 0;
						black = 0;
					}
					// the case that this is the first cell or the old cell is white
					else
					{
						last_color = 0;
					}
				}
				// the case that the cell is black
				else
				{
					// old cell is black or first or white
					last_color = 1;
					black++;
				}
			}
			
			// the case that the old cell was black
			if(last_color == 1)
			{
				// add the constraint
				curr_cons.add(black);
			}
			
			last_color = -1;
			black = 0;
			
			temp2 = col_cons.get(i);
			//the case that the number of constraint in this board col and the problem matches
			if(curr_cons.size() == temp2.size())
			{
				// for every constrint
				for(int k = 0; k < temp2.size(); k++)
				{
					// the case that the constriants matches
					if(curr_cons.get(k) == temp2.get(k))
					{
						fitness+=row_size;
					}
				}

			}
			curr_cons.clear();
		}
		
		return fitness;
	}

	/*
	 * this function transpose this chromosome's matrix
	 * @return - this Chromosome's matrix transposed
	 */
	private ArrayList<ArrayList<Integer>> transpose()
	{
		ArrayList<ArrayList<Integer>> board = new ArrayList<ArrayList<Integer>>();
		ArrayList<Integer> temp, temp2;
		
		// for every column
		for (int i = 0; i < board_sol.get(0).size(); i++) 
		{
			temp = new ArrayList<Integer>();
			// for every row
			for (int j = 0; j < board_sol.size(); j++) 
			{
				// create a dummy array
				temp.add(-1);
			}
			board.add(temp);	
		}
		
		// for every row
		for (int i = 0; i < board_sol.size(); i++) 
		{
			temp2 = board_sol.get(i);
			// for every column
			for (int j = 0; j < temp2.size(); j++) 
			{
				// update the transpose array
				board.get(j).set(i, temp2.get(j));
			}
		}
		return board;
	}
}
